package me.stone.stanimeclient.core.ui.binding.adapters

import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.view.ViewGroup
import android.widget.ImageView
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.databinding.BindingAdapter
import com.bumptech.glide.Glide
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import eightbitlab.com.blurview.BlurAlgorithm
import eightbitlab.com.blurview.BlurView
import eightbitlab.com.blurview.RenderEffectBlur
import eightbitlab.com.blurview.RenderScriptBlur
import me.stone.stanimeclient.core.common.di.MainExecutor
import me.stone.stanimeclient.core.common.di.NetworkExecutor
import me.stone.stanimeclient.core.ui.R
import timber.log.Timber
import java.util.concurrent.Executor
import java.util.concurrent.Executors
import javax.inject.Singleton


@BindingAdapter("srcUrl")
fun srcUrl(view: ImageView, url: String?) {
    if (url.isNullOrBlank()) {
        view.setImageResource(R.mipmap.empty_cover)
    } else {
        Glide.with(view).load(url).error(R.mipmap.empty_cover).into(view)
    }
}

@BindingAdapter("drawableResId")
fun drawableResId(view: ImageView, @DrawableRes resId: Int?) {
    resId?.takeIf { it != 0 }?.let {
        view.setImageResource(it)
    }
}


@BindingAdapter("blurImageFromUrl")
fun blurImageFromUrl(blurView: BlurView, url: String?) {
    val safeUrl = url.takeUnless { it.isNullOrBlank() } ?: return

    val algorithm: BlurAlgorithm =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            RenderEffectBlur()
        } else {
            RenderScriptBlur(blurView.context)
        }

    val request = Glide.with(blurView.context).load(safeUrl)
        .error(R.mipmap.empty_cover)
        .submit()

    Executors.newSingleThreadExecutor().execute {
        try {
            request.get()
        } catch (e: Exception) {
            Timber.e(e)
            AppCompatResources.getDrawable(blurView.context, R.mipmap.empty_cover)
        }?.let { drawable ->
            Handler(Looper.getMainLooper()).post {
                val parentGroup = blurView.parent as? ViewGroup ?: return@post
                parentGroup.background = drawable
                blurView.setupWith(parentGroup, algorithm)
                    .setFrameClearDrawable(drawable)
                    .setOverlayColor(Color.argb(0x66, 0, 0, 0))
                    .setBlurRadius(12f)
            }
        }
    }
}

@Module
@InstallIn(SingletonComponent::class)
object BlurImageHelperModule {
    @Singleton
    @Provides
    fun provides(
        @ApplicationContext context: Context,
        @NetworkExecutor networkExecutor: Executor,
        @MainExecutor mainExecutor: Executor
    ) : BlurImageHelper = BlurImageHelper(context, networkExecutor, mainExecutor)
}

@Suppress("UNUSED")
class BlurImageHelper (
    private val context: Context,
    private val networkExecutor: Executor,
    private val mainThreadExecutor: Executor
) {
    private val algorithm: BlurAlgorithm =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            RenderEffectBlur()
        } else {
            RenderScriptBlur(context)
        }

    fun setBlurFromUrl(blurView: BlurView, url: String, radius: Float = 30.0f) {
        val request = Glide.with(context).load(url)
            .error(R.mipmap.empty_cover)
            .submit()
        networkExecutor.execute {
            val drawable = try {
                request.get()
            } catch (e: Exception) {
                Timber.e(e)
                AppCompatResources.getDrawable(context, R.mipmap.empty_cover)
            }
            mainThreadExecutor.execute {
                drawable?.let { setBlurWithDrawable(blurView, it, radius) }
            }
        }
    }

    private fun setBlurWithDrawable(blurView: BlurView, drawable: Drawable, radius: Float) {
        val parentGroup = blurView.parent as? ViewGroup ?: return
        parentGroup.background = drawable
        blurView.setupWith(parentGroup, algorithm)
            .setFrameClearDrawable(drawable)
            .setOverlayColor(Color.argb(0x88, 0, 0, 0))
            .setBlurRadius(radius)
    }
}